#include "stm32f10x.h"                  
#include "AD.h"
#include "board.h"

void AD_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	
	/*设置ADC时钟*/
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频，ADCCLK = 72MHz / 6 = 12MHz
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0引脚初始化为模拟输入
	
	/*规则组通道配置*/
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);		//规则组序列1的位置，配置为通道0
	
	/*ADC初始化*/
	ADC_InitTypeDef ADC_InitStructure;						//定义结构体变量
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//模式，选择独立模式，即单独使用ADC1
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐，选择右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发，使用软件触发，不需要外部触发
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//连续转换，失能，每转换一次规则组序列后停止
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;			//扫描模式，失能，只转换规则组的序列1这一个位置
	ADC_InitStructure.ADC_NbrOfChannel = 1;					//通道数，为1，仅在扫描模式下，才需要指定大于1的数，在非扫描模式下，只能是1
	ADC_Init(ADC1, &ADC_InitStructure);						//将结构体变量交给ADC_Init，配置ADC1
	
	/*ADC使能*/
	ADC_Cmd(ADC1, ENABLE);									//使能ADC1，ADC开始运行
	
	/*ADC校准*/
	ADC_ResetCalibration(ADC1);								//固定流程，内部有电路会自动执行校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}

/**
  * 函    数：获取AD转换的值
  * 参    数：无
  * 返 回 值：AD转换的值，范围：0~4095
  */
uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位，即等待AD转换结束
	return ADC_GetConversionValue(ADC1);					//读数据寄存器，得到AD转换的结果
}

float ADC_to_angle(uint16_t adc_value) {
     // 检查 ADC 值是否在有效范围内
     if (adc_value < ADC_MIN) {
         adc_value = ADC_MIN;
     } else if (adc_value > ADC_MAX) {
         adc_value = ADC_MAX;
     }

     // 线性映射计算角度
     float angle = ANGLE_MIN + (float)(adc_value - ADC_MIN) * (ANGLE_MAX - ANGLE_MIN) / (ADC_MAX - ADC_MIN);
     return angle;
 }
/*
// 分段线性映射结构体
typedef struct {
    uint16_t adc_min;
    uint16_t adc_max;
    float angle_min;
    float angle_max;
} AngleMapSegment;

// 分段线性映射表
AngleMapSegment angle_map_segments[] = {
   // {0, 3, 0, 45},
    {3, 478, 45.0, 90.0},
    {478, 1324, 90.0, 135.0},
    {1324, 1890, 135.0, 180.0},
    {1890, 4095, 180.0, 315.0}
};

//角度转换
float ADC_to_angle(uint16_t adc_value) {
    // 检查 ADC 值是否在有效范围内
    if (adc_value < angle_map_segments[0].adc_min) {
        adc_value = angle_map_segments[0].adc_min;
    } else if (adc_value > angle_map_segments[sizeof(angle_map_segments) / sizeof(angle_map_segments[0]) - 1].adc_max) {
        adc_value = angle_map_segments[sizeof(angle_map_segments) / sizeof(angle_map_segments[0]) - 1].adc_max;
    }

    // 查找对应的分段
    for (int i = 0; i < sizeof(angle_map_segments) / sizeof(angle_map_segments[0]); i++) {
        if (adc_value >= angle_map_segments[i].adc_min && adc_value <= angle_map_segments[i].adc_max) {
            // 线性映射计算角度
            float angle = angle_map_segments[i].angle_min + (float)(adc_value - angle_map_segments[i].adc_min) * 
                          (angle_map_segments[i].angle_max - angle_map_segments[i].angle_min) / 
                          (angle_map_segments[i].adc_max - angle_map_segments[i].adc_min);
            return angle;
        }
    }
    return ANGLE_MIN;
}
*/
 // 角度专用的滑动平均滤波函数
uint16_t angle_sliding_average_filter(uint16_t new_value)
{
    static uint16_t angle_sum = 0;
    // 减去最早的值
    angle_sum -= angle_filter_buffer[angle_filter_index];
    // 加入新的值
    angle_filter_buffer[angle_filter_index] = new_value;
    angle_sum += new_value;
    // 更新索引
    angle_filter_index = (angle_filter_index + 1) % ANGLE_FILTER_WINDOW_SIZE;
    // 返回平均值
    return angle_sum / ANGLE_FILTER_WINDOW_SIZE;
}
